/*-------------------------------------------------------------------------
 *
 * spgist.h
 *      Public header file for SP-GiST access method.
 *
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/spgist.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef SPGIST_H
#define SPGIST_H

#include "access/amapi.h"
#include "access/xlogreader.h"
#include "fmgr.h"
#include "lib/stringinfo.h"


/* reloption parameters */
#define SPGIST_MIN_FILLFACTOR            10
#define SPGIST_DEFAULT_FILLFACTOR        80

/* SPGiST opclass support function numbers */
#define SPGIST_CONFIG_PROC                1
#define SPGIST_CHOOSE_PROC                2
#define SPGIST_PICKSPLIT_PROC            3
#define SPGIST_INNER_CONSISTENT_PROC    4
#define SPGIST_LEAF_CONSISTENT_PROC        5
#define SPGISTNProc                        5

/*
 * Argument structs for spg_config method
 */
typedef struct spgConfigIn
{
    Oid            attType;        /* Data type to be indexed */
} spgConfigIn;

typedef struct spgConfigOut
{
    Oid            prefixType;        /* Data type of inner-tuple prefixes */
    Oid            labelType;        /* Data type of inner-tuple node labels */
    bool        canReturnData;    /* Opclass can reconstruct original data */
    bool        longValuesOK;    /* Opclass can cope with values > 1 page */
} spgConfigOut;

/*
 * Argument structs for spg_choose method
 */
typedef struct spgChooseIn
{
    Datum        datum;            /* original datum to be indexed */
    Datum        leafDatum;        /* current datum to be stored at leaf */
    int            level;            /* current level (counting from zero) */

    /* Data from current inner tuple */
    bool        allTheSame;        /* tuple is marked all-the-same? */
    bool        hasPrefix;        /* tuple has a prefix? */
    Datum        prefixDatum;    /* if so, the prefix value */
    int            nNodes;            /* number of nodes in the inner tuple */
    Datum       *nodeLabels;        /* node label values (NULL if none) */
} spgChooseIn;

typedef enum spgChooseResultType
{
    spgMatchNode = 1,            /* descend into existing node */
    spgAddNode,                    /* add a node to the inner tuple */
    spgSplitTuple                /* split inner tuple (change its prefix) */
} spgChooseResultType;

typedef struct spgChooseOut
{
    spgChooseResultType resultType; /* action code, see above */
    union
    {
        struct                    /* results for spgMatchNode */
        {
            int            nodeN;    /* descend to this node (index from 0) */
            int            levelAdd;    /* increment level by this much */
            Datum        restDatum;    /* new leaf datum */
        }            matchNode;
        struct                    /* results for spgAddNode */
        {
            Datum        nodeLabel;    /* new node's label */
            int            nodeN;    /* where to insert it (index from 0) */
        }            addNode;
        struct                    /* results for spgSplitTuple */
        {
            /* Info to form new upper-level inner tuple with one child tuple */
            bool        prefixHasPrefix;    /* tuple should have a prefix? */
            Datum        prefixPrefixDatum;    /* if so, its value */
            int            prefixNNodes;    /* number of nodes */
            Datum       *prefixNodeLabels;    /* their labels (or NULL for no
                                             * labels) */
            int            childNodeN; /* which node gets child tuple */

            /* Info to form new lower-level inner tuple with all old nodes */
            bool        postfixHasPrefix;    /* tuple should have a prefix? */
            Datum        postfixPrefixDatum; /* if so, its value */
        }            splitTuple;
    }            result;
} spgChooseOut;

/*
 * Argument structs for spg_picksplit method
 */
typedef struct spgPickSplitIn
{
    int            nTuples;        /* number of leaf tuples */
    Datum       *datums;            /* their datums (array of length nTuples) */
    int            level;            /* current level (counting from zero) */
} spgPickSplitIn;

typedef struct spgPickSplitOut
{
    bool        hasPrefix;        /* new inner tuple should have a prefix? */
    Datum        prefixDatum;    /* if so, its value */

    int            nNodes;            /* number of nodes for new inner tuple */
    Datum       *nodeLabels;        /* their labels (or NULL for no labels) */

    int           *mapTuplesToNodes;    /* node index for each leaf tuple */
    Datum       *leafTupleDatums;    /* datum to store in each new leaf tuple */
} spgPickSplitOut;

/*
 * Argument structs for spg_inner_consistent method
 */
typedef struct spgInnerConsistentIn
{
    ScanKey        scankeys;        /* array of operators and comparison values */
    int            nkeys;            /* length of array */

    Datum        reconstructedValue; /* value reconstructed at parent */
    void       *traversalValue; /* opclass-specific traverse value */
    MemoryContext traversalMemoryContext;    /* put new traverse values here */
    int            level;            /* current level (counting from zero) */
    bool        returnData;        /* original data must be returned? */

    /* Data from current inner tuple */
    bool        allTheSame;        /* tuple is marked all-the-same? */
    bool        hasPrefix;        /* tuple has a prefix? */
    Datum        prefixDatum;    /* if so, the prefix value */
    int            nNodes;            /* number of nodes in the inner tuple */
    Datum       *nodeLabels;        /* node label values (NULL if none) */
} spgInnerConsistentIn;

typedef struct spgInnerConsistentOut
{
    int            nNodes;            /* number of child nodes to be visited */
    int           *nodeNumbers;    /* their indexes in the node array */
    int           *levelAdds;        /* increment level by this much for each */
    Datum       *reconstructedValues;    /* associated reconstructed values */
    void      **traversalValues;    /* opclass-specific traverse values */
} spgInnerConsistentOut;

/*
 * Argument structs for spg_leaf_consistent method
 */
typedef struct spgLeafConsistentIn
{
    ScanKey        scankeys;        /* array of operators and comparison values */
    int            nkeys;            /* length of array */

    Datum        reconstructedValue; /* value reconstructed at parent */
    void       *traversalValue; /* opclass-specific traverse value */
    int            level;            /* current level (counting from zero) */
    bool        returnData;        /* original data must be returned? */

    Datum        leafDatum;        /* datum in leaf tuple */
} spgLeafConsistentIn;

typedef struct spgLeafConsistentOut
{
    Datum        leafValue;        /* reconstructed original data, if any */
    bool        recheck;        /* set true if operator must be rechecked */
} spgLeafConsistentOut;


/* spgutils.c */
extern bytea *spgoptions(Datum reloptions, bool validate);

/* spginsert.c */
extern IndexBuildResult *spgbuild(Relation heap, Relation index,
         struct IndexInfo *indexInfo);
extern void spgbuildempty(Relation index);
extern bool spginsert(Relation index, Datum *values, bool *isnull,
          ItemPointer ht_ctid, Relation heapRel,
          IndexUniqueCheck checkUnique,
          struct IndexInfo *indexInfo);

/* spgscan.c */
extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz);
extern void spgendscan(IndexScanDesc scan);
extern void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
          ScanKey orderbys, int norderbys);
extern int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
extern bool spggettuple(IndexScanDesc scan, ScanDirection dir);
extern bool spgcanreturn(Relation index, int attno);

/* spgvacuum.c */
extern IndexBulkDeleteResult *spgbulkdelete(IndexVacuumInfo *info,
              IndexBulkDeleteResult *stats,
              IndexBulkDeleteCallback callback,
              void *callback_state);
extern IndexBulkDeleteResult *spgvacuumcleanup(IndexVacuumInfo *info,
                 IndexBulkDeleteResult *stats);

/* spgvalidate.c */
extern bool spgvalidate(Oid opclassoid);

#endif                            /* SPGIST_H */
